package com.xinyue.game.server.logic.player;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.RemovalListener;
import com.google.common.cache.RemovalNotification;
import com.xinyue.game.server.common.GameServerConfig;
import com.xinyue.game.server.dao.IDaoPlayerService;
import com.xinyue.game.server.dao.entity.PlayerEntity;
import com.xinyue.game.server.logic.player.event.LoginOutEvent;
import com.xinyue.game.utils.XyBeanCopyUtil;
import com.xinyue.server.framework.common.GameAsyncTaskService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.time.Duration;
import java.util.concurrent.ExecutionException;

/**
 * 角色信息缓存
 *
 * @author 王广帅
 * @date 2022/12/24 21:33
 */
@Service
public class PlayerCacheService {
    private Logger logger = LoggerFactory.getLogger(PlayerCacheService.class);
    private Cache<String, PlayerEntity> roleCache;
    @Autowired
    private IDaoPlayerService daoPlayerService;
    @Autowired
    private GameAsyncTaskService gameAsyncTaskService;

    @Autowired
    private GameServerConfig gameServerConfig;

    @PostConstruct
    public void init() {
        roleCache = CacheBuilder.newBuilder().expireAfterAccess(Duration.ofMinutes(gameServerConfig.getExpireOfAccess()))
                .initialCapacity(1000).maximumSize(gameServerConfig.getMaxCacheSize()).removalListener(new RemovalListener<String, PlayerEntity>() {
                    @Override
                    public void onRemoval(RemovalNotification<String, PlayerEntity> notification) {
                        logger.info("角色被从内存中移除，更新一次到数据库，playerId:{}", notification.getKey());
                        PlayerEntity playerEntity = notification.getValue();
                        flushPlayer(playerEntity);
                    }
                }).build();
    }

    public PlayerEntity getPlayerIfPresent(String playerId) {
        return this.roleCache.getIfPresent(playerId);
    }

    public void addRoleCache(PlayerEntity playerEntity) {
        this.roleCache.put(playerEntity.getPlayerId(), playerEntity);
    }

    public PlayerEntity getPlayerOrLoading(String playerId) {
        try {
            return this.roleCache.get(playerId, () -> this.daoPlayerService.getPlayerById(playerId));
        } catch (ExecutionException e) {
            logger.error("loading role from db error,playerId: {}", playerId, e);
        }
        return null;
    }

    public void flushPlayer(String roleId) {
        PlayerEntity playerEntity = this.getPlayerIfPresent(roleId);
        this.flushPlayer(playerEntity);
    }

    private void flushPlayer(PlayerEntity playerEntity) {
        if (playerEntity != null) {
            PlayerEntity newPlayerEntity = XyBeanCopyUtil.copyObj(playerEntity, PlayerEntity.class);
            gameAsyncTaskService.execute(String.valueOf(playerEntity.getPlayerId()), "更新role信息", () -> {
                this.daoPlayerService.updatePlayer(newPlayerEntity);
            });
        }
    }

    @EventListener
    public void logoutEvent(LoginOutEvent event) {
        // 用户下线时，刷新一下缓存
        this.flushPlayer(event.getPlayerId());
        logger.info("用户下线，刷新缓存,playerId:{},threadId:{}", event.getPlayerId(), Thread.currentThread().getId());
    }

}
